// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: jaewon

#pragma once

#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include <boost/functional/hash.hpp>

#include "coin/feed/fastfeed/feed.pb.h"
#include "coin1/fastfeed/view/base.h"

namespace fastfeed {
namespace view {
namespace detail {

template <typename T>
std::unique_ptr<ViewBase> CreateView() {
  return std::make_unique<T>();
}

}  // namespace detail

void RegisterViewType(
    const std::string& view_type,
    std::function<std::unique_ptr<ViewBase>()> creator,
    bool ignore_if_exists = false);

template <typename T>
void RegisterViewType(const std::string& view_type, bool ignore_if_exists = false) {
  RegisterViewType(view_type, detail::CreateView<T>, ignore_if_exists);
}

class ViewCollection {
 public:
  void SubscribeView(const ViewKey& view_key, std::function<void(const ViewBase*)> callback);

  void SubscribeFeed(
      proto::FeedType feed_type,
      const std::string& symbol,
      std::function<void(const proto::Feed&)> callback);

  void SubscribeCustomFeed(
      const std::string& custom_feed_type,
      const std::string& symbol,
      std::function<void(const proto::Feed&)> callback);

  void InvokeFeedCallbacks(const proto::Feed& feed);

 private:
  using FeedKey = std::pair<int32_t, std::string>;
  using CustomFeedKey = std::pair<std::string, std::string>;
  using FeedCallbackVector = std::vector<std::function<void(const proto::Feed&)>>;

  FeedKey feed_key_cache_;
  CustomFeedKey custom_feed_key_cache_;

  std::unordered_map<FeedKey, FeedCallbackVector, boost::hash<FeedKey>> feed_callbacks_;
  std::unordered_map<CustomFeedKey, FeedCallbackVector, boost::hash<CustomFeedKey>>
      custom_feed_callbacks_;

  std::unordered_map<ViewKey, std::unique_ptr<ViewBase>, boost::hash<ViewKey>> views_;
};  // class ViewCollection

}  // namespace view
}  // namespace fastfeed
